package cn.stimd.spring.aop.framework.autoproxy;

import cn.stimd.spring.aop.Advisor;
import cn.stimd.spring.aop.TargetSource;
import cn.stimd.spring.aop.framework.AbstractAutoProxyCreator;
import cn.stimd.spring.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.util.LinkedList;
import java.util.List;

/**
 * 通用的AutoProxyCreator，对所有Bean进行检测（潜含义就是可以与Spring IOC容器配合使用），并对侦测到Advisor的Bean构建aop代理。
 * 1. 子类可重写findCandidateAdvisors方法，返回作用于所有对象的自定义Advisor列表
 * 2。子类可重写shouldSkip方法，从自动代理中排除某些对象
 * 3. 需要排序可以实现Ordered接口，如果没有实现Ordered接口，Advice或Advisor将出现在Advisor链的末尾
 * <p>
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) {
        List<Advisor> eligibleAdvisors = findEligibleAdvisors(beanClass);
        if (eligibleAdvisors.isEmpty()) {
            return null;
        }
        return eligibleAdvisors.toArray();
    }


    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass) {
        //1. 从BeanFactory寻找候选的Advisor集合
        List<Advisor> candidateAdvisors = findCandidateAdvisors();

        //2. 过滤出符合当前类的所有Advisor
        List<Advisor> eligibleAdvisors = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);

        //3.  排序
        if (!eligibleAdvisors.isEmpty()) {
            AnnotationAwareOrderComparator.sort(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }


    //查找候选的Advisor Bean
    protected List<Advisor> findCandidateAdvisors(){
        List<String> advisorNames = getBeanFactory().getBeanNamesForType(Advisor.class);
        List<Advisor> advisors = new LinkedList<>();
        for (String name : advisorNames) {
            if (isEligibleAdvisorBean(name)) {
                //从容器中获取Advisor组件，并添加到候选列表中
                advisors.add(getBeanFactory().getBean(name, Advisor.class));
            }
        }
        return advisors;
    }


    /**
     * 检查Advisor Bean是否用于代理，默认为true，子类可重写
     */
    protected boolean isEligibleAdvisorBean(String beanName) {
        return true;
    }
}
